/* 
 * Copyright 2014 Igor Maznitsa (http://www.igormaznitsa.com).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.igormaznitsa.prol.easygui;

import com.igormaznitsa.prol.easygui.AbstractProlEditor.PropertyLink;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;

/**
 * The class implements a small dialog window contains the tree which allows
 * user to change values of different IDE parts because it is a very specialized
 * auxiliary class, it is not described very precisely
 *
 * @author Igor Maznitsa (igor.maznitsa@igormaznitsa.com)
 */
public class OptionsDialog extends javax.swing.JDialog implements TreeSelectionListener, TreeModel {

  private static final long serialVersionUID = 6189268173338687096L;

  private final ArrayList<TreeModel> items;
  private final ArrayList<TreeModelListener> treeModelListeners;

  private static final class TreeRenderer extends DefaultTreeCellRenderer {

    private static final long serialVersionUID = 4008482488500265205L;

    private static final Icon close_Icon = UIUtils.loadIcon("folder_wrench");
    private static final Icon open_Icon = UIUtils.loadIcon("folder");
    private static final Icon leaf_Icon = UIUtils.loadIcon("wrench");

    @Override
    public Icon getLeafIcon() {
      return leaf_Icon;
    }

    @Override
    public Icon getClosedIcon() {
      return close_Icon;
    }

    @Override
    public Icon getOpenIcon() {
      return open_Icon;
    }
  }

  /**
   * Creates new form OptionsDialog
   *
   * @param parent
   * @param items
   */
  public OptionsDialog(final java.awt.Frame parent, final TreeModel[] items) {
    super(parent, true);
    initComponents();

    treeModelListeners = new ArrayList<TreeModelListener>();

    this.items = new ArrayList<TreeModel>();
    for (final TreeModel model : items) {
      this.items.add(model);
    }

    optionsTree.setModel(this);
    optionsTree.setCellRenderer(new TreeRenderer());
    optionsTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
    optionsTree.addTreeSelectionListener(this);
  }

  /**
   * This method is called from within the constructor to initialize the form.
   * WARNING: Do NOT modify this code. The content of this method is always
   * regenerated by the Form Editor.
   */
  @SuppressWarnings("unchecked")
  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
  private void initComponents() {

    jScrollPane1 = new javax.swing.JScrollPane();
    optionsTree = new javax.swing.JTree();
    buttonEditOption = new javax.swing.JButton();
    buttonCloseDialog = new javax.swing.JButton();

    setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
    setTitle("Options");
    setLocationByPlatform(true);

    optionsTree.setRootVisible(false);
    optionsTree.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseClicked(java.awt.event.MouseEvent evt) {
        optionsTreeMouseClicked(evt);
      }
    });
    jScrollPane1.setViewportView(optionsTree);

    buttonEditOption.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/cog_edit.png"))); // NOI18N
    buttonEditOption.setText("Edit");
    buttonEditOption.setToolTipText("Edit or change the selected option");
    buttonEditOption.setEnabled(false);
    buttonEditOption.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        buttonEditOptionActionPerformed(evt);
      }
    });

    buttonCloseDialog.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/cross.png"))); // NOI18N
    buttonCloseDialog.setText("Close");
    buttonCloseDialog.setToolTipText("Close the dialog");
    buttonCloseDialog.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        buttonCloseDialogActionPerformed(evt);
      }
    });

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(layout.createSequentialGroup()
        .addContainerGap()
        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
          .addComponent(jScrollPane1)
          .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
            .addComponent(buttonEditOption, javax.swing.GroupLayout.PREFERRED_SIZE, 112, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(buttonCloseDialog, javax.swing.GroupLayout.PREFERRED_SIZE, 135, javax.swing.GroupLayout.PREFERRED_SIZE)))
        .addContainerGap())
    );

    layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonCloseDialog, buttonEditOption});

    layout.setVerticalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
        .addContainerGap()
        .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 349, Short.MAX_VALUE)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
          .addComponent(buttonEditOption)
          .addComponent(buttonCloseDialog))
        .addContainerGap())
    );

    pack();
  }// </editor-fold>//GEN-END:initComponents

    private void buttonCloseDialogActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonCloseDialogActionPerformed
      dispose();
    }//GEN-LAST:event_buttonCloseDialogActionPerformed

    private void buttonEditOptionActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonEditOptionActionPerformed
      final TreePath path = optionsTree.getSelectionPath();
      if (path == null) {
        return;
      }
      final AbstractProlEditor.PropertyLink prop = (PropertyLink) path.getLastPathComponent();
      final Object val = prop.getProperty();
      if (val instanceof Font) {
        final FontChooserDialog dialog = new FontChooserDialog(this, "Tune the font for \'" + prop.toString() + "\'", (Font) val, "?-repeat,write('Hello world'),nl,fail.\r\n:-X is 2*2,write(X).");
        dialog.setVisible(true);
        final Font font = dialog.getResult();
        if (font != null) {
          prop.setProperty(font);
        }
      }
      else if (val instanceof Color) {
        final Color color = (Color) val;
        JColorChooser chooser = new JColorChooser(color);

        final boolean[] array = new boolean[1];

        ActionListener actionListenerOk = new ActionListener() {

          @Override
          public void actionPerformed(ActionEvent e) {
            array[0] = true;
          }
        };

        JDialog colorChooser = JColorChooser.createDialog(this, "Choose color for \'" + prop.toString() + "\'", true, chooser, actionListenerOk, null);
        colorChooser.setVisible(true);
        if (array[0]) {
          prop.setProperty(chooser.getColor());
        }
      }
      else if (val instanceof Boolean) {
        prop.setProperty((Boolean) (!(Boolean) val));
      }

      firePropertyChanged(path);

    }//GEN-LAST:event_buttonEditOptionActionPerformed

  private void optionsTreeMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_optionsTreeMouseClicked
    final JTree tree = (JTree) evt.getSource();
    int selRow = tree.getRowForLocation(evt.getX(), evt.getY());
    final TreePath selPath = tree.getPathForLocation(evt.getX(), evt.getY());
    if (selRow != -1) {
      if (evt.getClickCount() == 2) {
        if (buttonEditOption.isEnabled()) {
          buttonEditOption.doClick();
        }
      }
    }
  }//GEN-LAST:event_optionsTreeMouseClicked

  // Variables declaration - do not modify//GEN-BEGIN:variables
  private javax.swing.JButton buttonCloseDialog;
  private javax.swing.JButton buttonEditOption;
  private javax.swing.JScrollPane jScrollPane1;
  private javax.swing.JTree optionsTree;
  // End of variables declaration//GEN-END:variables

  @Override
  public void valueChanged(final TreeSelectionEvent e) {
    TreePath path = optionsTree.getSelectionPath();
    if (path != null) {

      buttonEditOption.setEnabled(path.getLastPathComponent() instanceof AbstractProlEditor.PropertyLink);
      return;
    }

    buttonEditOption.setEnabled(false);
  }

  @Override
  public Object getRoot() {
    return this;
  }

  @Override
  public Object getChild(Object parent, int index) {
    if (this.equals(parent)) {
      return items.get(index);
    }
    else {
      return ((TreeModel) parent).getChild(parent, index);
    }
  }

  @Override
  public int getChildCount(Object parent) {
    if (this.equals(parent)) {
      return items.size();
    }
    else {
      return ((TreeModel) parent).getChildCount(parent);
    }
  }

  @Override
  public boolean isLeaf(final Object node) {
    return node instanceof AbstractProlEditor.PropertyLink;
  }

  @Override
  public void valueForPathChanged(TreePath path, Object newValue) {
  }

  @Override
  public int getIndexOfChild(Object parent, Object child) {
    if (this.equals(parent)) {
      return items.indexOf(child);
    }
    else {
      return ((TreeModel) parent).getIndexOfChild(parent, child);
    }

  }

  private void firePropertyChanged(TreePath path) {
    for (TreeModelListener listener : treeModelListeners) {
      listener.treeNodesChanged(new TreeModelEvent(this, path));
    }
  }

  @Override
  public void addTreeModelListener(TreeModelListener l) {
    treeModelListeners.add(l);
  }

  @Override
  public void removeTreeModelListener(TreeModelListener l) {
    treeModelListeners.remove(l);
  }

}
